package com.hospital.diagnosis.module.service.impl;

import com.hospital.common.dto.payment.module.OrderCreateDto;
import com.hospital.common.enums.diagnosis.module.SessionStatus;
import com.hospital.common.enums.payment.module.OrderType;
import com.hospital.common.pojo.TChatLog;
import com.hospital.common.pojo.TChatSession;
import com.hospital.common.pojo.TDepartment;
import com.hospital.diagnosis.module.exception.ServiceException;
import com.hospital.diagnosis.module.feign.PaymentFeign;
import com.hospital.diagnosis.module.mapper.ChatMapper;
import com.hospital.diagnosis.module.service.ChatService;
import com.hospital.diagnosis.module.utils.JsonUtils;
import com.hospital.diagnosis.module.utils.RedisUtils;
import com.hospital.diagnosis.module.vo.ChatSessionVo;
import com.hospital.diagnosis.module.vo.ChatVo;
import com.hospital.diagnosis.module.vo.DoctorVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static com.hospital.diagnosis.module.utils.WebSocketUtils.sendMessage;

@Service
public class ChatServiceImpl implements ChatService
{
    @Autowired
    private ChatMapper chatMapper;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private PaymentFeign paymentFeign;

    @Override
    public List<TDepartment> getDepartments()
    {
        return chatMapper.getDepartments();
    }

    @Override
    public List<DoctorVo> getDoctors(Long departmentId)
    {
        return chatMapper.getDoctors(departmentId);
    }

    @Override
    public Boolean updateChatStatus(String sessionId, Integer status)
    {
        TChatSession chatSession=(TChatSession) redisUtils.hGet("chat",sessionId);
        if(chatSession==null){
            throw new ServiceException("会话不存在");
        }

        if(status.equals(SessionStatus.PAY_FAILED.value)){
            redisUtils.hDel("chat",sessionId);
            return true;
        }

        //更新会话状态
        chatSession.setSessionStatus(status);
        chatSession.setCreateTime(LocalDateTime.now());
        redisUtils.hSet("chat",sessionId,chatSession);

        //更新医生端会话列表
        Long doctorId = chatSession.getDoctorId();
        if(doctorId!=null){
            List<TChatSession> chats= getChats(doctorId);
            ChatVo chatVo = new ChatVo(0,chats);
            String chatsJson = JsonUtils.toJson(chatVo);
            sendMessage(doctorId,chatsJson);
        }

        //更新患者端会话列表
        Long patientId = chatSession.getPatientId();
        if(patientId!=null){
            List<TChatSession> chats= getChats(patientId);
            ChatVo chatVo = new ChatVo(0,chats);
            String chatsJson = JsonUtils.toJson(chatVo);
            sendMessage(patientId,chatsJson);
        }

        return true;
    }

    @Override
    public Boolean createChat(Long doctorId, Long patientId)
    {
        List<Double> doctorCost = chatMapper.getDoctorCost(doctorId);
        if(doctorCost.size()==0){
            throw new ServiceException("无法获取线上诊疗费用");
        }
        Double cost = doctorCost.get(0);
        String sessionId = UUID.randomUUID().toString();
        if(!(paymentFeign.createOnlineDiagnosis(new OrderCreateDto(patientId, OrderType.ONLINE_DIAGNOSIS.value, null,cost, sessionId)).getCode()==1))
        {
            throw new ServiceException("创建订单失败");
        }

        //创建会话
        TChatSession chatSession = new TChatSession();
            chatSession.setSessionId(sessionId);
            chatSession.setDoctorId(doctorId);
            chatSession.setPatientId(patientId);
            chatSession.setSessionStatus(SessionStatus.NOT_PAY.value);
            chatSession.setCreateTime(LocalDateTime.now());
            chatSession.setDoctorUnreadCount(0);
            chatSession.setPatientUnreadCount(0);
        redisUtils.hSet("chat",chatSession.getSessionId(),chatSession);

        //更新医生端会话列表
        List<TChatSession> chats= getChats(doctorId);
        ChatVo chatVo = new ChatVo(0,chats);
        String chatsJson = JsonUtils.toJson(chatVo);
        sendMessage(doctorId,chatsJson);

        //更新患者端会话列表
        chats= getChats(patientId);
        chatVo = new ChatVo(0,chats);
        chatsJson = JsonUtils.toJson(chatVo);
        sendMessage(patientId,chatsJson);

        return true;
    }

    @Override
    public List<TChatSession> getChats(Long userId)
    {
        Map<Object, Object> chatMap = redisUtils.hGetAll("chat");
        List<TChatSession> chats=chatMap.values()
                .stream()
                .map(value->(TChatSession)value)
                .filter(o->o.getPatientId().equals(userId)||o.getDoctorId().equals(userId))
                .toList();

        return chats;
    }

    @Override
    public List<TChatSession> getChats()
    {
        Map<Object, Object> chatMap = redisUtils.hGetAll("chat");
        List<TChatSession> chats=chatMap.values()
                .stream()
                .map(value->(TChatSession)value)
                .toList();
        return chats;
    }

    @Override
    public List<ChatSessionVo> getChatSessionVo(List<TChatSession> chats) {
        return chats.stream()
                .map(chatSession -> {
                    ChatSessionVo chatSessionVo = new ChatSessionVo();
                    chatSessionVo.setId(chatSession.getId());
                    chatSessionVo.setSessionId(chatSession.getSessionId());
                    chatSessionVo.setDoctorId(chatSession.getDoctorId());
                    chatSessionVo.setDoctorName(getUserNameById(chatSession.getDoctorId()));
                    chatSessionVo.setPatientId(chatSession.getPatientId());
                    chatSessionVo.setPatientName(getUserNameById(chatSession.getPatientId()));
                    chatSessionVo.setChatEvaluationId(chatSession.getChatEvaluationId());
                    chatSessionVo.setSessionStatus(chatSession.getSessionStatus());
                    chatSessionVo.setCreateTime(chatSession.getCreateTime());
                    chatSessionVo.setPatientUnreadCount(chatSession.getPatientUnreadCount());
                    chatSessionVo.setDoctorUnreadCount(chatSession.getDoctorUnreadCount());
                    return chatSessionVo;
                })
                .toList();
    }


    @Override
    public void archiveChat(TChatSession chatSession)
    {
        chatMapper.archiveChatSession(chatSession);
        redisUtils.hDel("chat",chatSession.getSessionId());
        redisUtils.getList("chatSessions:"+chatSession.getSessionId())
                .stream()
                .map(value->(TChatLog)value)
                .forEach(chatLog -> {chatMapper.archiveChatLog(chatLog);});
        redisUtils.del("chatSessions:"+chatSession.getSessionId());
    }

    @Override
    public List<TChatSession> getArchivedChats(Long userId)
    {
        return chatMapper.getArchivedChats(userId);
    }

    @Override
    public String getUserNameById(Long userId) {
        return chatMapper.getUserNameById(userId);
    }

    @Override
    public List<TChatLog> getChatLogsBySessionId(String sessionId)
    {
        return chatMapper.getChatLogsBySessionId(sessionId);
    }

    @Override
    public List<DoctorVo> getAllDoctors(Long departmentId) {

        return chatMapper.getAllDoctors(departmentId);
    }

    @Override
    public List<ChatSessionVo> getAllArchivedChats(Long doctorId, String patientName, String startTime, String endTime, Integer pageNum, Integer pageSize) {
        List<TChatSession> chats=chatMapper.getALLArchivedChats(doctorId,patientName,startTime,endTime,(pageNum-1)*pageSize,pageSize);
        return getChatSessionVo(chats);
    }

    @Override
    public Integer getAllArchivedChatsCount(Long doctorId, String patientName, String startTime, String endTime) {
        return chatMapper.getALLArchivedChatsCount(doctorId,patientName,startTime,endTime);
    }

    @Override
    public Integer getUnreadCount(Long doctorId) {
        List<TChatSession> chats= getChats(doctorId);
        return chats.stream()
                .mapToInt(TChatSession::getDoctorUnreadCount)
                .sum();
    }


}
